package gao.xiaolei.service;

import gao.xiaolei.dao.BugAttachedDao;
import gao.xiaolei.dao.TestBugDao;
import gao.xiaolei.dao.TestRequirementDao;
import gao.xiaolei.dto.BugOutDto;
import gao.xiaolei.entity.BugAttached;
import gao.xiaolei.entity.TestBug;
import gao.xiaolei.exception.AuthException;
import gao.xiaolei.util.Md5;
import gao.xiaolei.util.ServiceName;
import gao.xiaolei.util.UuidUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import xiaolei.gao.Image.ImageInterface;
import xiaolei.gao.file.FileInterface;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;

@Service("TestBugService")
public class TestBugService {
    @Resource(name = "TestBugDao")
    private TestBugDao testBugDao;

    @Resource(name = "BugAttachedDao")
    private BugAttachedDao bugAttachedDao;

    @Resource(name = "FileInterface")
    private FileInterface fileInterface;

    @Resource(name = "ImageInterface")
    private ImageInterface imageInterface;

    @Autowired
    private RestTemplate restTemplate;

    @Resource(name = "TestRequirementDao")
    private TestRequirementDao testRequirementDao;

    @Resource(name = "AnalysisService")
    private AnalysisService analysisService;

    @Transactional
    public TestBug addTestBug(String id, String toTrq, String title, String author, String projectId, String describe, MultipartFile[] attachedFiles) throws IOException {
        LocalDateTime now = LocalDateTime.now();
        testBugDao.save(new TestBug(id, toTrq, title, author, projectId, describe, now, now));//先保存bug本身信息
        Map<String, Boolean> hashOrUuidList = new LinkedHashMap<>(4);//用于储存文件的uuid或者hash码,因为要保证文件操作在最后才做
        for (int i = 0, length = attachedFiles.length; i < length; i++) {
            String originalFilename = attachedFiles[i].getOriginalFilename();
            String fileName = originalFilename.substring(originalFilename.lastIndexOf("/") + 1);
            boolean isImage = getIsImage(originalFilename);
            String hashOrUuid = null;
            if (isImage)
                hashOrUuid = Md5.md5HashCode32(attachedFiles[i].getBytes());//图片则自己生成Hash码
            else
                hashOrUuid = UuidUtil.get32Uuid();
            hashOrUuidList.put(hashOrUuid, isImage);
            bugAttachedDao.save(new BugAttached(UuidUtil.get32Uuid(), id, fileName, isImage ? 0 : 1, hashOrUuid));//保存附件信息
        }
        TestBug bug = testBugDao.findById(id).get();
        analysisService.doAnalysis(projectId);
        int i = 0;
        for (Map.Entry<String, Boolean> wu : hashOrUuidList.entrySet()) {//最后再去保存文件，因为文件操作无法回退
            if (wu.getValue())
                imageInterface.imageUploadWithDefineHashCode(attachedFiles[i++], wu.getKey());
            else
                fileInterface.fileUpload(attachedFiles[i++], wu.getKey());
        }
        return bug;
    }

    @Transactional
    public TestBug updateTestBug(String id, String toTrq, String title, String author, String projectId, String describe, List<String> newAttachedIds, MultipartFile[] newAttachedFiles, String currentUserId) throws IOException {
        TestBug oldBug = testBugDao.findById(id).orElseThrow(() -> new IllegalArgumentException("该bug("
                .concat(id)
                .concat(")不存在！")));
        if (!oldBug.getAuthor().equals(currentUserId))
            throw new AuthException("该bug你没有权限修改！");
        List<BugAttached> oldAttached = bugAttachedDao.findAllByToBug(id);
        Map<String, Integer> willDeleteFile = new HashMap<>();//记录等一下要删除的文件Uuid和文件类型
        Map<String, Boolean> willUploadFile = new LinkedHashMap<>();//记录等一下要上传的文件Uuid和文件类型，为了实现插入顺序和遍历顺序一致，所以使用LinkedHashMap
        if (newAttachedIds == null)
            newAttachedIds = new ArrayList<>(0);//防止空指针异常
        boolean isDelete, isAdd;
        String oldAttaId = null, newAttaId = null;
        int i, j, length, length2;
        for (i = 0, length = oldAttached.size(); i < length; i++) {//比较旧附件列表是否有新附件列表所没有的
            isDelete = true;
            oldAttaId = oldAttached.get(i).getId();
            for (j = 0, length2 = newAttachedIds.size(); j < length2; j++) {
                if (oldAttaId.equals(newAttachedIds.get(j))) {
                    isDelete = false;//如果新列表里面也有的话说明就不要删除
                    break;
                }
            }
            if (isDelete) {
                bugAttachedDao.deleteById(oldAttaId);
                willDeleteFile.put(oldAttached.get(i).getFileUuid(), oldAttached.get(i).getType());
            }
        }
        int addCount = -1;//记录现在是第几个新添加的文件
        for (i = 0, length = newAttachedIds.size(); i < length; i++) {//查看新附件列表里面是否有旧列表里没有的
            isAdd = true;
            newAttaId = newAttachedIds.get(i);
            for (j = 0, length2 = oldAttached.size(); j < length2; j++) {
                if (newAttaId.equals(oldAttached.get(j).getId())) {
                    isAdd = false;//如果旧的里面也有的话说明就不用添加
                    break;
                }
            }
            if (isAdd) {
                addCount++;
                String originalFilename = newAttachedFiles[addCount].getOriginalFilename();
                String fileName = originalFilename.substring(originalFilename.lastIndexOf("/") + 1);
                boolean isImage = getIsImage(originalFilename);
                String hashOrUuid = null;
                if (isImage)
                    hashOrUuid = Md5.md5HashCode32(newAttachedFiles[addCount].getBytes());//图片则自己生成Hash码
                else
                    hashOrUuid = UuidUtil.get32Uuid();
                bugAttachedDao.save(new BugAttached(UuidUtil.get32Uuid(), id, fileName, isImage ? 0 : 1, hashOrUuid));//保存附件信息
                willUploadFile.put(hashOrUuid, isImage);
            }
        }
        TestBug newBug = new TestBug(id, toTrq, title, author, projectId, describe, oldBug.getCreateDate(), LocalDateTime.now());
        testBugDao.save(newBug);//保存bug本身信息
        analysisService.doAnalysis(projectId);
        for (Map.Entry<String, Integer> wd : willDeleteFile.entrySet()) {//依次调用文件服务去删除文件
            if (wd.getValue() == 0)
                imageInterface.imageDelete(wd.getKey());
            else
                fileInterface.fileDelete(wd.getKey());
        }
        i = 0;
        for (Map.Entry<String, Boolean> wu : willUploadFile.entrySet()) {//依次调用文件服务去上传文件
            if (wu.getValue())
                imageInterface.imageUploadWithDefineHashCode(newAttachedFiles[i++], wu.getKey());
            else
                fileInterface.fileUpload(newAttachedFiles[i++], wu.getKey());
        }
        return newBug;
    }

    //获取项目已经提交的bug列表
    @Transactional(readOnly = true)
    public List<TestBug> getBugListBuProjectId(String projectId) {
        List<TestBug> projectBug = testBugDao.findAllByProjectId(projectId);
        for (int i = 0, length = projectBug.size(); i < length; i++) {
            String authorName = restTemplate.getForObject(ServiceName.AUTH_SERVICE.getServiceName().concat("/user/realName/").concat(projectBug.get(i).getAuthor()), String.class);
            projectBug.get(i).setAuthorName(authorName);
            projectBug.get(i).setTrqName(projectBug.get(i).getToTrq().concat(getTrqPath(projectBug.get(i).getToTrq())));
        }
        return projectBug;
    }

    //获取bug的详细信息
    @Transactional(readOnly = true)
    public BugOutDto getBugDetail(String id) {
        TestBug bug = testBugDao.findById(id).orElseThrow(() -> new IllegalArgumentException("该bug("
                .concat(id)
                .concat(")不存在！")));
        List<BugAttached> attacheds = bugAttachedDao.findAllByToBug(id);
        String authorName = restTemplate.getForObject(ServiceName.AUTH_SERVICE.getServiceName().concat("/user/realName/").concat(bug.getAuthor()), String.class);
        bug.setAuthorName(authorName);
        String trqName = getTrqPath(bug.getToTrq());
        bug.setTrqName(trqName);
        return new BugOutDto(bug, attacheds);
    }

    //删除bug
    @Transactional
    public void deleteBug(List<String> ids, String currentUserId) {
        List<TestBug> bugs = testBugDao.findAllById(ids);
        Map<String, Integer> willDeleteFile = new HashMap<>();
        int i, j, length, length2;
        for (i = 0, length = bugs.size(); i < length; i++) {
            if (!bugs.get(i).getAuthor().equals(currentUserId))
                throw new AuthException("该bug你没有权限删除！");
            List<BugAttached> attacheds = bugAttachedDao.findAllByToBug(bugs.get(i).getId());
            for (j = 0, length2 = attacheds.size(); j < length2; j++) {
                willDeleteFile.put(attacheds.get(j).getFileUuid(), attacheds.get(j).getType());
            }
            bugAttachedDao.deleteAll(attacheds);
        }
        testBugDao.deleteAll(bugs);
        if (bugs.size() > 0)
            analysisService.doAnalysis(bugs.get(0).getProjectId());
        for (Map.Entry<String, Integer> wd : willDeleteFile.entrySet()) {
            if (wd.getValue() == 0)
                imageInterface.imageDelete(wd.getKey());
            else
                fileInterface.fileDelete(wd.getKey());
        }
    }

    @Transactional(readOnly = true)
    //下载附件
    public ResponseEntity<byte[]> downloadAttached(String attachedId) throws UnsupportedEncodingException {
        BugAttached attached = bugAttachedDao.findById(attachedId).orElseThrow(() -> (new IllegalArgumentException("附件"
                .concat(attachedId)
                .concat("不存在！"))));
        MultiValueMap<String, String> header = new LinkedMultiValueMap<>(1);
        header.add("content-disposition", "attachment;filename=" + URLEncoder.encode(attached.getName(), "UTF-8"));
        byte[] fileByte = null;
        if (attached.getType() == 0)
            fileByte = imageInterface.getImage(attached.getFileUuid());
        else
            fileByte = fileInterface.getFile(attached.getFileUuid());
        return new ResponseEntity<byte[]>(fileByte, header, HttpStatus.OK);
    }

    @Transactional
    //给BUG打分
    public void gradeBug(String id, int grade) {
        testBugDao.updateGrade(id, grade);
    }

    private boolean getIsImage(String originalFilename) {
        String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1).toLowerCase();
        boolean isImage = false;
        if ("jpg".equals(suffix) || "gif".equals(suffix) || "jpeg".equals(suffix) || "png".equals(suffix))
            isImage = true;
        return isImage;
    }

    //获取某一个测试需求的路径
    private String getTrqPath(String trqId) {
        List<String> path = new LinkedList<>();
        String parentId = testRequirementDao.getParentId(trqId);
        while (!"root".equals(parentId) && parentId != null) {
            path.add(testRequirementDao.getTitle(parentId));
            parentId = testRequirementDao.getParentId(parentId);
        }
        StringBuilder result = new StringBuilder();
        for (int i = path.size() - 1; i >= 0; i--) {
            result.append(path.get(i)).append("/");
        }
        result.append(testRequirementDao.getTitle(trqId));
        return result.toString();
    }
}
